package com.iplant.aps.serviceImpl.utils.aps;

import com.iplant.aps.service.apsenum.aps.APSMsgTypes;
import com.iplant.aps.service.apsenum.aps.APSShiftPeriod;
import com.iplant.aps.service.apsenum.aps.APSTaskStatus;
import com.iplant.aps.service.apsenum.oms.OMSOrderPriority;
import com.iplant.aps.service.apsenum.oms.OMSOrderStatus;
import com.iplant.aps.service.po.aps.*;
import com.iplant.aps.service.po.oms.OMSOrder;
import com.iplant.aps.service.po.sch.APSDoneMinSchedule;
import com.iplant.aps.service.po.sch.APSMarginCapacityAndResult;
import com.iplant.aps.service.po.sch.APSMarginEntityCapacity;
import com.iplant.aps.service.po.sch.APSMessage;
import com.iplant.base.po.OutResult;
import com.iplant.base.po.Pagination;
import com.iplant.base.po.ServiceResult;
import com.iplant.base.utils.cache.CacheUtils;
import com.iplant.base.utils.general.CalendarTool;
import com.iplant.base.utils.general.StringUtils;
import com.iplant.basic.service.po.bms.BMSEmployee;
import com.iplant.basic.service.po.cfg.CFGCalendar;
import com.iplant.basic.service.po.fmc.*;
import com.iplant.basic.serviceImpl.CFGServiceImpl;
import com.iplant.basic.serviceImpl.FMCServiceImpl;
import com.iplant.pdm.service.basicenum.fpc.FPCRouteType;
import com.iplant.pdm.service.po.bop.FPCRoute;
import com.iplant.pdm.service.po.bop.FPCRoutePart;
import com.iplant.pdm.service.po.bop.FPCRoutePartPoint;
import com.iplant.pdm.service.po.fpc.FPCCapacity;
import com.iplant.pdm.service.po.fpc.FPCProduct;
import com.iplant.pdm.service.po.mss.MSSBOMItem;
import com.iplant.pdm.serviceImpl.FPCServiceImpl;
import com.iplant.pdm.serviceImpl.dao.fpc.FPCProductDAO;
import com.iplant.pdm.serviceImpl.dao.fpc.FPCRouteDAO;
import com.iplant.pdm.serviceImpl.dao.fpc.FPCRoutePartDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.stream.Collectors;

public class iPlantScheduleUtils {
    private static final Logger logger = LoggerFactory.getLogger(iPlantScheduleUtils.class);

    public iPlantScheduleUtils() {
    }

    private static iPlantScheduleUtils Instance;

    public static iPlantScheduleUtils getInstance() {
        if (Instance == null)
            Instance = new iPlantScheduleUtils();
        return Instance;
    }


    public Map<Integer, Calendar> CloneCalendar(Map<Integer, Calendar> wValue) {
        Map<Integer, Calendar> wResult = new HashMap<>();
        for (Integer wKey : wValue.keySet()) {
            wResult.put(wKey, CalendarTool.CloneDateTime(wValue.get(wKey)));
        }
        return wResult;
    }

    /**
     * 设置订单优先级
     */
    public List<OMSOrder> APS_SetOrderPriority(List<OMSOrder> wOrderList,
                                               List<OMSOrderPriority> wOrderPriorityList, List<Integer> wLineOrders,
                                               List<Integer> wCustomerOrders,
                                               List<Integer> wProductIDs) {
        try {
            // 局段顺序
            // 修程顺序
            if (wOrderList == null || wOrderList.size() == 0)
                return wOrderList;

            if (wOrderPriorityList == null || wOrderPriorityList.size() == 0)
                return wOrderList;

            for (int i = wOrderPriorityList.size() - 1; i >= 0; i--) {
                OMSOrderPriority wOrderPriority = wOrderPriorityList.get(i);
                switch (wOrderPriority) {
                    case Default:
                        break;
                    case RealReceiveDate:

                        wOrderList
                                .sort(Comparator.comparing((OMSOrder p) -> p.Status).reversed().thenComparing(o -> o.PlanReceiveDate));
                        break;
                    case Line:
                        if (wLineOrders == null || wLineOrders.size() == 0)
                            break;
                        wOrderList.sort((o1, o2) -> {
                            int wIndex1 = wLineOrders.indexOf(o1.getLineID());
                            int wIndex2 = wLineOrders.indexOf(o2.getLineID());
                            if (wIndex1 == -1) {
                                wIndex1 = wLineOrders.size();
                            }
                            if (wIndex2 == -1) {
                                wIndex2 = wLineOrders.size();
                            }
                            return wIndex1 - wIndex2;
                        });

                        break;
                    case PlanFinishDate:
                        wOrderList.sort(Comparator.comparing(o -> o.PlanFinishDate));
                        break;
                    case BureauSection:
                        if (wCustomerOrders == null || wCustomerOrders.size() == 0)
                            break;
                        wOrderList.sort((o1, o2) -> {

                            int wIndex1 = wCustomerOrders.indexOf(o1.CustomerID);
                            int wIndex2 = wCustomerOrders.indexOf(o2.CustomerID);
                            if (wIndex1 == -1) {
                                wIndex1 = wCustomerOrders.size();
                            }
                            if (wIndex2 == -1) {
                                wIndex2 = wCustomerOrders.size();
                            }
                            return wIndex1 - wIndex2;
                        });
                        break;
                    case ProductNo:
                        if (wProductIDs == null || wProductIDs.size() == 0)
                            break;
                        wOrderList.sort((o1, o2) -> {
                            int wIndex1 = wProductIDs.indexOf(o1.getProductID());
                            int wIndex2 = wProductIDs.indexOf(o2.getProductID());
                            if (wIndex1 == -1) {
                                wIndex1 = wProductIDs.size();
                            }
                            if (wIndex2 == -1) {
                                wIndex2 = wProductIDs.size();
                            }
                            return wIndex1 - wIndex2;
                        });
                        break;
                    default:
                        break;
                }
            }

            int wPriority = wOrderList.size();
            for (OMSOrder wOMSOrder : wOrderList) {
                wOMSOrder.Priority = wPriority;
                wPriority--;
            }

            // 订单优先级只与当前需要比较的订单列表中有效 并不存储
        } catch (Exception e) {
            logger.error(e.toString());
        }
        return wOrderList;
    }


    public Map<Integer, List<FPCRoutePart>> GetFPCRoutePartListMap(Map<Integer, FPCRoute> wOrderRouteMap) {
        Map<Integer, List<FPCRoutePart>> wResult = new HashMap<>();
        for (Integer wInteger : wOrderRouteMap.keySet()) {
            wResult.put(wInteger, wOrderRouteMap.get(wInteger).PartList);
        }
        return wResult;
    }


    /**
     * 检查订单工艺   //函数完成  BOP置为当前时检查
     *
     * @param wLoginUser
     * @param wOrderList
     * @param wAPSShiftPeriod
     * @param wEntityIDList   需要将涉及到的实体全部完善
     * @param wMaterilIDList  需要将涉及到的物料全部完善
     * @param wOrderRouteMap  将订单涉及到的工艺全部完善
     * @param wFPCProductMap  涉及到的产品全部完善
     * @param wAPSMessage
     */
    public void CheckOrderRoute(BMSEmployee wLoginUser, List<OMSOrder> wOrderList, APSShiftPeriod wAPSShiftPeriod,
                                FPCRouteType wFPCRouteType,
                                List<Integer> wEntityIDList, List<Integer> wMaterilIDList,
                                Map<Integer, FPCRoute> wOrderRouteMap,
                                Map<Integer, FPCProduct> wFPCProductMap, List<APSMessage> wAPSMessage) {

        OutResult<Integer> wErrorCode = new OutResult<>(0);
        Map<Integer, FPCRoute> wFPCRouteMap = new HashMap<>();
        //检查订单工艺配置是否完善
        FPCRoute wFPCRoute;
        FPCProduct wFPCProduct;


        List<OMSOrder> wAllowOrder = new ArrayList<>();

        for (OMSOrder wOMSOrder : wOrderList) {
            if (wOMSOrder == null)
                continue;
            if (wOMSOrder.ID <= 0 || wOMSOrder.ProductID <= 0 || wOMSOrder.RouteID <= 0 || wOMSOrder.FQTYPlan <= 0) {
                wAPSMessage.add(new APSMessage(APSMsgTypes.Lack.getValue(), wOMSOrder.ID, wOMSOrder.LineID,
                        wOMSOrder.ProductCode,
                        StringUtils.Format("订单{0}工艺字段数据不全，请补全工艺再排程", wOMSOrder.Code)));
                continue;
            }
            if (wAPSShiftPeriod != APSShiftPeriod.Week && wOMSOrder.Status >= OMSOrderStatus.Producing.getValue()) {
                wAPSMessage.add(new APSMessage(APSMsgTypes.Lack.getValue(), wOMSOrder.ID, wOMSOrder.LineID,
                        wOMSOrder.ProductCode,
                        StringUtils.Format("订单{0}已开工，无法重排计划", wOMSOrder.Code)));
                continue;
            }

            //产品配置是否完全
            if (wFPCProductMap.containsKey(wOMSOrder.ProductID)) {
                wFPCProduct = wFPCProductMap.get(wOMSOrder.ProductID);
            } else {

                wFPCProduct = FPCProductDAO.getInstance().SelectPO(wLoginUser, wOMSOrder.ProductID, "",
                        wErrorCode);

                //todo en 查询产品信息  并检查产品质量标准配置是否配置（质量配置中，包含工艺配置，可用一个字段区别）;  通过置位当前BOP检查
                //todo en 不通过 wAPSMessage.add()
                wFPCProductMap.put(wOMSOrder.ProductID, wFPCProduct);
            }
            //工艺是否存在
            if (wFPCRouteMap.containsKey(wOMSOrder.RouteID)) {
                wFPCRoute = wFPCRouteMap.get(wOMSOrder.RouteID);
                wOrderRouteMap.put(wOMSOrder.ID, wFPCRoute);
            } else {
                wFPCRoute = FPCRouteDAO.getInstance().FPC_QueryRoute(wLoginUser, wOMSOrder.RouteID, wErrorCode);

                // todo  en  通过置位当前BOP检查
                // todo  en 查询BOP  并检查BOP完整性; 检查工步项点是否涵盖所有质量标准配置

                //todo  en  wAPSMessage.add()  continue;

                this.SetEntityAndMaterialIDs(wFPCRoute, wFPCRouteType, wEntityIDList, wMaterilIDList);

                wFPCRouteMap.put(wOMSOrder.RouteID, wFPCRoute);
                wOrderRouteMap.put(wOMSOrder.ID, wFPCRoute);
            }

            //检查通过 加入允许排程订单列表
            wAllowOrder.add(wOMSOrder);
        }
        wOrderList.clear();
        wOrderList.addAll(wAllowOrder);


    }


    /**
     * 检查工艺工序
     *
     * @param wLoginUser
     * @param wAPSShiftPeriod
     * @param wEntityIDList   需要将涉及到的工位全部完善
     * @param wMaterilIDList  需要将涉及到的物料全部完善
     * @param wAPSMessage
     */
    public void CheckRoutePart(BMSEmployee wLoginUser, List<APSTaskPart> wAPSTaskPartList,
                               APSShiftPeriod wAPSShiftPeriod,
                               List<Integer> wEntityIDList, List<Integer> wMaterilIDList,
                               Map<Integer, FPCRoutePart> wRoutePartMap,
                               Map<Integer, FPCProduct> wFPCProductMap, List<APSMessage> wAPSMessage) {

        OutResult<Integer> wErrorCode = new OutResult<>(0);
        //检查订单工艺配置是否完善
        FPCRoutePart wFPCRoute;
        FPCProduct wFPCProduct;

        List<APSTaskPart> wAllowOrder = new ArrayList<>();

        for (APSTaskPart wAPSTaskPart : wAPSTaskPartList) {
            if (wAPSTaskPart == null)
                continue;

            if (wAPSTaskPart.ProductID <= 0 || wAPSTaskPart.RoutePartID <= 0 || wAPSTaskPart.OrderID <= 0) {
                wAPSMessage.add(new APSMessage(APSMsgTypes.Lack.getValue(), wAPSTaskPart.OrderID, wAPSTaskPart.LineID
                        , wAPSTaskPart.ProductCode,
                        StringUtils.Format("计划{0}工艺{1}数据不合法，请补全工艺计划再试", wAPSTaskPart.OrderNo,
                                wAPSTaskPart.RoutePartName)));
                continue;
            }
            if (wAPSShiftPeriod == APSShiftPeriod.Month && wAPSTaskPart.Status >= APSTaskStatus.Started.getValue()) {
                wAPSMessage.add(new APSMessage(APSMsgTypes.Lack.getValue(), wAPSTaskPart.OrderID, wAPSTaskPart.LineID
                        , wAPSTaskPart.ProductCode,
                        StringUtils.Format("订单：{0}的计划{1}已开工，无法重排计划", wAPSTaskPart.OrderNo,
                                wAPSTaskPart.RoutePartName)));
                continue;
            }
            //产品配置是否完全
            if (!wFPCProductMap.containsKey(wAPSTaskPart.ProductID)) {

                wFPCProduct = FPCProductDAO.getInstance().SelectPO(wLoginUser, wAPSTaskPart.ProductID, "",
                        wErrorCode);

                if (wFPCProduct == null || wFPCProduct.ID <= 0) {
                    wAPSMessage.add(new APSMessage(APSMsgTypes.Lack.getValue(), wAPSTaskPart.OrderID,
                            wAPSTaskPart.LineID, wAPSTaskPart.ProductCode,
                            StringUtils.Format("订单：{0}的产品{1}不存在，无法生成计划", wAPSTaskPart.OrderNo,
                                    wAPSTaskPart.ProductCode)));
                    continue;
                }

                wFPCProductMap.put(wAPSTaskPart.ProductID, wFPCProduct);
            }

            //工艺是否存在
            if (!wRoutePartMap.containsKey(wAPSTaskPart.RoutePartID)) {


                wFPCRoute = FPCRoutePartDAO.getInstance().FPC_QueryRoutePart(wLoginUser, wAPSTaskPart.RoutePartID, ""
                        , wErrorCode);

                if (wFPCRoute == null || wFPCRoute.ID <= 0 || wFPCRoute.PartPointList == null || wFPCRoute.PartPointList.size() == 0) {
                    wAPSMessage.add(new APSMessage(APSMsgTypes.Lack.getValue(), wAPSTaskPart.OrderID,
                            wAPSTaskPart.LineID, wAPSTaskPart.ProductCode,
                            StringUtils.Format("订单：{0}的工艺{1}不存在，无法生成计划", wAPSTaskPart.OrderNo,
                                    wAPSTaskPart.RoutePartName)));
                    continue;
                }
                wRoutePartMap.put(wAPSTaskPart.RoutePartID, wFPCRoute);
            }
            this.SetEntityAndMaterialIDs(wRoutePartMap.get(wAPSTaskPart.RoutePartID), wEntityIDList, wMaterilIDList);

            //检查通过 加入允许排程订单列表
            wAllowOrder.add(wAPSTaskPart);
        }
        wAPSTaskPartList.clear();
        wAPSTaskPartList.addAll(wAllowOrder);
    }

    private void SetEntityAndMaterialIDs(FPCRoute wFPCRoute, FPCRouteType wFPCRouteType, List<Integer> wEntityIDList,
                                         List<Integer> wMaterilIDList) {
        if (wFPCRoute != null || wFPCRoute.PartList != null && wFPCRoute.PartList.size() > 0) {

            switch (wFPCRouteType) {
                case RoutePartPoint:
                    for (FPCRoutePart wFPCRoutePart : wFPCRoute.PartList) {
                        this.SetEntityAndMaterialIDs(wFPCRoutePart, wEntityIDList, wMaterilIDList);
                    }
                    break;
                case RoutePartWorkshop:
                case RoutePartWorkArea:
                case RoutePartStation:
                    for (FPCRoutePart wFPCRoutePart : wFPCRoute.PartList) {
                        if (wFPCRoutePart == null)
                            continue;
                        wEntityIDList.add(wFPCRoutePart.getPartEntityID());

                        if (wFPCRoutePart.PartPointList == null || wFPCRoutePart.PartPointList.size() == 0)
                            continue;
                        for (FPCRoutePartPoint wFPCRoutePartPoint : wFPCRoutePart.PartPointList) {
                            if (wFPCRoutePartPoint == null || wFPCRoutePartPoint.BOMItemList == null || wFPCRoutePartPoint.BOMItemList.size() == 0)
                                continue;

                            for (MSSBOMItem wMSSBOMItem : wFPCRoutePartPoint.BOMItemList) {
                                if (wMSSBOMItem == null)
                                    continue;
                                wMaterilIDList.add(wMSSBOMItem.MaterialID);
                            }
                        }
                    }
                    break;
                case Default:
                    break;
            }
        }
    }

    private void SetEntityAndMaterialIDs(FPCRoutePart wFPCRoutePart, List<Integer> wEntityIDList,
                                         List<Integer> wMaterilIDList) {
        if (wFPCRoutePart != null || wFPCRoutePart.PartPointList != null && wFPCRoutePart.PartPointList.size() > 0) {

            for (FPCRoutePartPoint wFPCRoutePartPoint : wFPCRoutePart.PartPointList) {
                if (wFPCRoutePartPoint == null)
                    continue;
                wEntityIDList.addAll(wFPCRoutePartPoint.StationID);

                if (wFPCRoutePartPoint.BOMItemList == null || wFPCRoutePartPoint.BOMItemList.size() == 0)
                    continue;

                for (MSSBOMItem wMSSBOMItem : wFPCRoutePartPoint.BOMItemList) {
                    if (wMSSBOMItem == null)
                        continue;
                    wMaterilIDList.add(wMSSBOMItem.MaterialID);
                }
            }
        }
    }


    /**
     * @param wLoginUser
     * @param wOrderList
     * @param wFPCRoutePartListMap
     * @param wMarginRoutePartListMap
     * @param wAPSTaskPartDoneListMap
     * @param wMarginEntityCapacityMap
     * @param wAPSMessage
     * @return
     */
    public List<APSTaskPart> APS_AutoTaskPart(BMSEmployee wLoginUser, List<OMSOrder> wOrderList,
                                              APSShiftPeriod wAPSShiftPeriod,
                                              Map<Integer, List<FPCRoutePart>> wFPCRoutePartListMap, Map<Integer,
            List<List<FPCRoutePart>>> wMarginRoutePartListMap,
                                              Map<Integer, List<APSTaskPart>> wAPSTaskPartDoneListMap, Map<Integer,
            APSMarginEntityCapacity> wMarginEntityCapacityMap,
                                              int wAllowTechDelayHour, List<APSMessage> wAPSMessage,
                                              Calendar wStartDate, Calendar wEndDate) {

        List<APSTaskPart> wResult = new ArrayList<APSTaskPart>();

        Map<Integer, FPCRoutePart> wOrderRoutePartMap = new HashMap<Integer, FPCRoutePart>();
        List<List<FPCRoutePart>> wMarginRoutePartList = new ArrayList<>();
        List<APSTaskPart> wOrderTaskPartList = null;
        Map<Integer, APSTaskPart> wOrderTaskPartMap = null;
        Map<Integer, APSTaskPart> wDoneTaskPartMap = null;
        List<APSTaskPart> wAPSTaskPart = new ArrayList<>();


        APSMarginCapacityAndResult wAPSMarginCapacityAndResult =
                new APSMarginCapacityAndResult(wMarginEntityCapacityMap, true);

        // Map<Integer, Calendar> wStartedPartDate = new HashMap<>();
        Calendar wRouteStartDate;
        Calendar wPartStartDate;
        Calendar wPlanCalendar = CalendarTool.CloneDateTime(wStartDate);
        for (OMSOrder wOMSOrder : wOrderList) {
            wOrderRoutePartMap =
                    wFPCRoutePartListMap.get(wOMSOrder.RouteID).stream().collect(Collectors.toMap(p -> p.ID, p -> p,
                            (o1, o2) -> o1));
            wMarginRoutePartList = wMarginRoutePartListMap.get(wOMSOrder.ID);
            wOrderTaskPartMap = new HashMap<>();
            if (wAPSTaskPartDoneListMap.containsKey(wOMSOrder.ID)) {
                wDoneTaskPartMap =
                        wAPSTaskPartDoneListMap.get(wOMSOrder.ID).stream().collect(Collectors.toMap(p -> p.RoutePartID, p -> p, (o1, o2) -> o1));
            } else {
                wDoneTaskPartMap = new HashMap<>();
            }
            wOrderTaskPartMap.putAll(wDoneTaskPartMap);
            wAPSMarginCapacityAndResult.ClearResult();
            wPlanCalendar = CalendarTool.CloneDateTime(wStartDate);
            // 预计进厂日期
            if ((wOMSOrder.Status == OMSOrderStatus.HasOrder.getValue()
                    || wOMSOrder.Status == OMSOrderStatus.ProductReady.getValue()
                    || wOMSOrder.Status == OMSOrderStatus.PlanReady.getValue())
                    && wPlanCalendar.compareTo(wOMSOrder.PlanReceiveDate) < 0) {
                wPlanCalendar = CalendarTool.CloneDateTime(wOMSOrder.PlanReceiveDate);
            }

            wMarginRoutePartList.sort((o1, o2) -> o2.size() - o1.size());


            float wMarginCapacityT = 0;

            //获取最小批量
            List<APSDoneMinSchedule> wPrevPartMinScheduleMap =
                    iPlantSchedulePartTools.getInstance().GetPrevPartMinSchduleList(wDoneTaskPartMap,
                            wOMSOrder.FQTYPlan);


            //获取待排程初始工艺 只需要一个就够了
            if (wMarginRoutePartList.size() == 0 || wMarginRoutePartList.get(0).size() == 0) {

                //剩余无任务 无需重排
                continue;
            }

            FPCRoutePart wFPCRoutePart = wMarginRoutePartList.get(0).get(0);

            wRouteStartDate = CalendarTool.CloneDateTime(wPlanCalendar);

            if (wPrevPartMinScheduleMap != null && wPrevPartMinScheduleMap.size() > 0) {

                while (CalendarTool.CompareDate(wRouteStartDate, wEndDate) <= 0) {

                    while (wPrevPartMinScheduleMap.size() > 0) {

                        wMarginCapacityT = wPrevPartMinScheduleMap.get(0).MinPlan;


                        wMarginCapacityT -= iPlantSchedulePartTools.getInstance().GetPartMaxCapacity(wLoginUser,
                                wPrevPartMinScheduleMap.get(0).TechnologyList, wPlanCalendar, wRouteStartDate,
                                wMarginCapacityT,
                                wAPSMarginCapacityAndResult, wOrderRoutePartMap, 0, wFPCRoutePart, false,
                                wAllowTechDelayHour);


                        wAPSMarginCapacityAndResult.AddToTotal();


                        if (wMarginCapacityT > 0) {
                            //当日产能不够
                            wPrevPartMinScheduleMap.get(0).MinPlan = wMarginCapacityT;
                            break;
                        } else {
                            //产能足够
                            wPrevPartMinScheduleMap.remove(0);
                        }

                    }
                    if (wPrevPartMinScheduleMap.size() == 0) {
                        break;
                    }

                    wRouteStartDate.add(Calendar.DAY_OF_MONTH, 1);
                }
                if (wPrevPartMinScheduleMap.size() > 0) {

                    wAPSMessage.add(new APSMessage(APSMsgTypes.Capacity.getValue(), wOMSOrder.ID, wOMSOrder.LineID,
                            wOMSOrder.ProductCode,

                            StringUtils.Format("订单：{0} 排程时产能不足未排完！", wOMSOrder.Code)));
                }

            } else {
                wMarginCapacityT = wOMSOrder.FQTYPlan;
                while (CalendarTool.CompareDate(wRouteStartDate, wEndDate) <= 0) {

                    wMarginCapacityT -= iPlantSchedulePartTools.getInstance().GetPartMaxCapacity(wLoginUser,
                            new HashMap<>(), wPlanCalendar, wRouteStartDate, wMarginCapacityT,
                            wAPSMarginCapacityAndResult, wOrderRoutePartMap, 0, wFPCRoutePart, false,
                            wAllowTechDelayHour);

                    wAPSMarginCapacityAndResult.AddToTotal();

                    if (wMarginCapacityT <= 0)
                        break;
                    wRouteStartDate.add(Calendar.DAY_OF_MONTH, 1);
                }
                if (wMarginCapacityT > 0) {
                    wAPSMessage.add(new APSMessage(APSMsgTypes.Capacity.getValue(), wOMSOrder.ID, wOMSOrder.LineID,
                            wOMSOrder.ProductCode,

                            StringUtils.Format("订单：{0} 排程时产能不足未排完！", wOMSOrder.Code)));

                }
            }

            wOrderTaskPartList = wAPSMarginCapacityAndResult.CreateAPSTaskPartList(wLoginUser, wAPSShiftPeriod,
                    wOMSOrder, wOrderRoutePartMap);

            wResult.addAll(wOrderTaskPartList);
        }
        return wResult;
    }


    /**
     * @param wLoginUser
     * @param wOrderList
     * @param wFPCRoutePartPointListMap
     * @param wMarginRoutePartPointListMap
     * @param wAPSTaskPartPointDoneListMap
     * @param wMarginEntityCapacityMap
     * @param wAPSMessage
     * @param wStartDate
     * @param wEndDate
     * @return
     */
    public List<APSTaskPart> APS_AutoTaskPartPoint(BMSEmployee wLoginUser, List<OMSOrder> wOrderList,
                                                   APSShiftPeriod wAPSShiftPeriod,
                                                   Map<Integer, List<FPCRoutePartPoint>> wFPCRoutePartPointListMap,
                                                   Map<Integer, List<FPCRoutePart>> wFPCRoutePartListMap,
                                                   Map<Integer, List<List<FPCRoutePartPoint>>> wMarginRoutePartPointListMap,
                                                   Map<Integer, List<APSTaskPartPoint>> wAPSTaskPartPointDoneListMap,

                                                   Map<Integer, APSMarginEntityCapacity> wMarginEntityCapacityMap,
                                                   int wAllowTechDelayHour,
                                                   List<APSMessage> wAPSMessage, Calendar wStartDate,
                                                   Calendar wEndDate) {

        List<APSTaskPart> wResult = new ArrayList<APSTaskPart>();

        Map<Integer, FPCRoutePartPoint> wOrderRoutePartPointMap = new HashMap<Integer, FPCRoutePartPoint>();
        List<List<FPCRoutePartPoint>> wMarginRoutePartPointList = new ArrayList<>();
        List<APSTaskPartPoint> wOrderTaskPartPointList = null;
        Map<Integer, APSTaskPartPoint> wDoneTaskPartPointMap = null;

        APSMarginCapacityAndResult wAPSMarginCapacityAndResult =
                new APSMarginCapacityAndResult(wMarginEntityCapacityMap, true);
        Map<Integer, FPCRoutePart> wOrderRoutePartMap = new HashMap<Integer, FPCRoutePart>();


        Calendar wRouteStartDate;
        Calendar wPlanCalendar = CalendarTool.CloneDateTime(wStartDate);
        for (OMSOrder wOMSOrder : wOrderList) {
            wOrderRoutePartPointMap =
                    wFPCRoutePartPointListMap.get(wOMSOrder.RouteID).stream().collect(Collectors.toMap(p -> p.ID,
                            p -> p, (o1, o2) -> o1));

            wOrderRoutePartMap =
                    wFPCRoutePartListMap.get(wOMSOrder.RouteID).stream().collect(Collectors.toMap(p -> p.ID,
                            p -> p, (o1, o2) -> o1));

            wMarginRoutePartPointList = wMarginRoutePartPointListMap.get(wOMSOrder.ID);

            if (wAPSTaskPartPointDoneListMap.containsKey(wOMSOrder.ID)) {
                wDoneTaskPartPointMap =
                        wAPSTaskPartPointDoneListMap.get(wOMSOrder.ID).stream().collect(Collectors.toMap(p -> p.RoutePartPointID, p -> p, (o1, o2) -> o1));
            } else {
                wDoneTaskPartPointMap = new HashMap<>();
            }


            wAPSMarginCapacityAndResult.ClearResult();

            wPlanCalendar = CalendarTool.CloneDateTime(wStartDate);
            // 预计进厂日期
            if ((wOMSOrder.Status == OMSOrderStatus.HasOrder.getValue()
                    || wOMSOrder.Status == OMSOrderStatus.ProductReady.getValue()
                    || wOMSOrder.Status == OMSOrderStatus.PlanReady.getValue())
                    && wPlanCalendar.compareTo(wOMSOrder.PlanReceiveDate) < 0) {
                wPlanCalendar = CalendarTool.CloneDateTime(wOMSOrder.PlanReceiveDate);
            }

            wMarginRoutePartPointList.sort((o1, o2) -> o2.size() - o1.size());


            float wMarginCapacityT = 0;

            //获取最小批量
            List<APSDoneMinSchedule> wPrevPartPointMinScheduleMap =
                    iPlantSchedulePartPointTools.getInstance().GetPrevPartPointMinSchduleList(wDoneTaskPartPointMap,
                            wOMSOrder.FQTYPlan);


            //获取待排程初始工艺 只需要一个就够了
            if (wMarginRoutePartPointList.size() == 0 || wMarginRoutePartPointList.get(0).size() == 0) {

                //剩余无任务 无需重排
                continue;
            }

            FPCRoutePartPoint wFPCRoutePartPoint = wMarginRoutePartPointList.get(0).get(0);

            wRouteStartDate = CalendarTool.CloneDateTime(wPlanCalendar);

            Map<Integer, Map<String, Float>> wResultMap = new HashMap<>();
            if (wPrevPartPointMinScheduleMap != null && wPrevPartPointMinScheduleMap.size() > 0) {
                while (CalendarTool.CompareDate(wRouteStartDate, wEndDate) <= 0) {

                    int wLength = wPrevPartPointMinScheduleMap.size();
                    for (int i = 0; i < wLength; i++) {
                        wMarginCapacityT = wPrevPartPointMinScheduleMap.get(i).MinPlan;


                        wMarginCapacityT -= iPlantSchedulePartPointTools.getInstance().GetPartPointMaxCapacity(wLoginUser,
                                wPrevPartPointMinScheduleMap.get(i).TechnologyList, wPlanCalendar, wRouteStartDate,
                                wMarginCapacityT,
                                wAPSMarginCapacityAndResult, wOrderRoutePartPointMap, 0, wFPCRoutePartPoint, false,
                                wAllowTechDelayHour);

                        if (wMarginCapacityT > 0) {
                            //当日产能不够
                            wPrevPartPointMinScheduleMap.get(i).MinPlan = wMarginCapacityT;
                            break;
                        } else {
                            //产能足够
                            wPrevPartPointMinScheduleMap.remove(i);
                            i--;
                            wLength--;
                        }

                    }
                    if (wPrevPartPointMinScheduleMap.size() == 0)
                        break;

                    wRouteStartDate.add(Calendar.DAY_OF_MONTH, 1);
                }
                if (wPrevPartPointMinScheduleMap.size() > 0) {
                    wAPSMessage.add(new APSMessage(APSMsgTypes.Capacity.getValue(), wOMSOrder.ID, wOMSOrder.LineID,
                            wOMSOrder.ProductCode,

                            StringUtils.Format("订单：{0} 排程时产能不足未排完！", wOMSOrder.Code)));
                }

            } else {
                wMarginCapacityT = wOMSOrder.FQTYPlan;
                while (CalendarTool.CompareDate(wRouteStartDate, wEndDate) <= 0) {


                    wMarginCapacityT -= iPlantSchedulePartPointTools.getInstance().GetPartPointMaxCapacity(wLoginUser,
                            new HashMap<>(), wPlanCalendar, wRouteStartDate, wMarginCapacityT,
                            wAPSMarginCapacityAndResult, wOrderRoutePartPointMap, 0, wFPCRoutePartPoint, false,
                            wAllowTechDelayHour);


                    wAPSMarginCapacityAndResult.AddToTotal();

                    if (wMarginCapacityT <= 0)
                        break;
                    wRouteStartDate.add(Calendar.DAY_OF_MONTH, 1);
                }
                if (wMarginCapacityT > 0) {
                    wAPSMessage.add(new APSMessage(APSMsgTypes.Capacity.getValue(), wOMSOrder.ID, wOMSOrder.LineID,
                            wOMSOrder.ProductCode,

                            StringUtils.Format("订单：{0} 排程时产能不足未排完！", wOMSOrder.Code)));
                }
            }
            wOrderTaskPartPointList = wAPSMarginCapacityAndResult.CreateAPSTaskPartPointList(wLoginUser,
                    wAPSShiftPeriod, wOMSOrder, wOrderRoutePartPointMap);

            if (wOrderTaskPartPointList != null && wOrderTaskPartPointList.size() > 0) {

                wResult.addAll(iPlantSchedulePartTools.getInstance().CreateAPSTaskPartList(wLoginUser, wAPSShiftPeriod,
                        wOMSOrder, wOrderRoutePartMap, wOrderTaskPartPointList, wDoneTaskPartPointMap));
            }
        }
        return wResult;
    }


    /**
     * @param wLoginUser
     * @param wOrderList
     * @param wFPCRoutePartPointListMap
     * @param wMarginRoutePartPointListMap
     * @param wAPSTaskPartPointDoneListMap
     * @param wMarginEntityCapacityMap
     * @param wAPSMessage
     * @param wStartDate
     * @param wEndDate
     * @return
     */
    public List<APSTaskPartPoint> APS_AutoTaskPartPoint(BMSEmployee wLoginUser, List<OMSOrder> wOrderList,
                                                        APSShiftPeriod wAPSShiftPeriod,
                                                        Map<Integer, List<FPCRoutePartPoint>> wFPCRoutePartPointListMap,
                                                        Map<Integer, List<List<FPCRoutePartPoint>>> wMarginRoutePartPointListMap,
                                                        Map<Integer, List<APSTaskPartPoint>> wAPSTaskPartPointDoneListMap,

                                                        Map<Integer, APSMarginEntityCapacity> wMarginEntityCapacityMap, int wAllowTechDelayHour,
                                                        List<APSMessage> wAPSMessage, Calendar wStartDate,
                                                        Calendar wEndDate) {

        List<APSTaskPartPoint> wResult = new ArrayList<APSTaskPartPoint>();

        Map<Integer, FPCRoutePartPoint> wOrderRoutePartPointMap = new HashMap<Integer, FPCRoutePartPoint>();
        List<List<FPCRoutePartPoint>> wMarginRoutePartPointList = new ArrayList<>();
        List<APSTaskPartPoint> wOrderTaskPartPointList = null;
        Map<Integer, APSTaskPartPoint> wDoneTaskPartPointMap = null;

        APSMarginCapacityAndResult wAPSMarginCapacityAndResult =
                new APSMarginCapacityAndResult(wMarginEntityCapacityMap, true);
        Map<Integer, FPCRoutePart> wOrderRoutePartMap = new HashMap<Integer, FPCRoutePart>();


        Calendar wRouteStartDate;
        Calendar wPlanCalendar = CalendarTool.CloneDateTime(wStartDate);
        for (OMSOrder wOMSOrder : wOrderList) {
            wOrderRoutePartPointMap =
                    wFPCRoutePartPointListMap.get(wOMSOrder.RouteID).stream().collect(Collectors.toMap(p -> p.ID,
                            p -> p, (o1, o2) -> o1));


            wMarginRoutePartPointList = wMarginRoutePartPointListMap.get(wOMSOrder.ID);

            if (wAPSTaskPartPointDoneListMap.containsKey(wOMSOrder.ID)) {
                wDoneTaskPartPointMap =
                        wAPSTaskPartPointDoneListMap.get(wOMSOrder.ID).stream().collect(Collectors.toMap(p -> p.RoutePartPointID, p -> p, (o1, o2) -> o1));
            } else {
                wDoneTaskPartPointMap = new HashMap<>();
            }


            wAPSMarginCapacityAndResult.ClearResult();

            wPlanCalendar = CalendarTool.CloneDateTime(wStartDate);
            // 预计进厂日期
            if ((wOMSOrder.Status == OMSOrderStatus.HasOrder.getValue()
                    || wOMSOrder.Status == OMSOrderStatus.ProductReady.getValue()
                    || wOMSOrder.Status == OMSOrderStatus.PlanReady.getValue())
                    && wPlanCalendar.compareTo(wOMSOrder.PlanReceiveDate) < 0) {
                wPlanCalendar = CalendarTool.CloneDateTime(wOMSOrder.PlanReceiveDate);
            }

            wMarginRoutePartPointList.sort((o1, o2) -> o2.size() - o1.size());


            float wMarginCapacityT = 0;

            //获取最小批量
            List<APSDoneMinSchedule> wPrevPartPointMinScheduleMap =
                    iPlantSchedulePartPointTools.getInstance().GetPrevPartPointMinSchduleList(wDoneTaskPartPointMap,
                            wOMSOrder.FQTYPlan);


            //获取待排程初始工艺 只需要一个就够了
            if (wMarginRoutePartPointList.size() == 0 || wMarginRoutePartPointList.get(0).size() == 0) {

                //剩余无任务 无需重排
                continue;
            }

            FPCRoutePartPoint wFPCRoutePartPoint = wMarginRoutePartPointList.get(0).get(0);

            wRouteStartDate = CalendarTool.CloneDateTime(wPlanCalendar);

            Map<Integer, Map<String, Float>> wResultMap = new HashMap<>();
            if (wPrevPartPointMinScheduleMap != null && wPrevPartPointMinScheduleMap.size() > 0) {
                while (CalendarTool.CompareDate(wRouteStartDate, wEndDate) <= 0) {

                    int wLength = wPrevPartPointMinScheduleMap.size();
                    for (int i = 0; i < wLength; i++) {
                        wMarginCapacityT = wPrevPartPointMinScheduleMap.get(i).MinPlan;


                        wMarginCapacityT -= iPlantSchedulePartPointTools.getInstance().GetPartPointMaxCapacity(wLoginUser,
                                wPrevPartPointMinScheduleMap.get(i).TechnologyList, wPlanCalendar, wRouteStartDate,
                                wMarginCapacityT,
                                wAPSMarginCapacityAndResult, wOrderRoutePartPointMap, 0, wFPCRoutePartPoint, false,
                                wAllowTechDelayHour);

                        if (wMarginCapacityT > 0) {
                            //当日产能不够
                            wPrevPartPointMinScheduleMap.get(i).MinPlan = wMarginCapacityT;
                            break;
                        } else {
                            //产能足够
                            wPrevPartPointMinScheduleMap.remove(i);
                            i--;
                            wLength--;
                        }

                    }
                    if (wPrevPartPointMinScheduleMap.size() == 0)
                        break;

                    wRouteStartDate.add(Calendar.DAY_OF_MONTH, 1);
                }
                if (wPrevPartPointMinScheduleMap.size() > 0) {
                    wAPSMessage.add(new APSMessage(APSMsgTypes.Capacity.getValue(), wOMSOrder.ID, wOMSOrder.LineID,
                            wOMSOrder.ProductCode,

                            StringUtils.Format("订单：{0} 排程时产能不足未排完！", wOMSOrder.Code)));
                }

            } else {
                wMarginCapacityT = wOMSOrder.FQTYPlan;
                while (CalendarTool.CompareDate(wRouteStartDate, wEndDate) <= 0) {


                    wMarginCapacityT -= iPlantSchedulePartPointTools.getInstance().GetPartPointMaxCapacity(wLoginUser,
                            new HashMap<>(), wPlanCalendar, wRouteStartDate, wMarginCapacityT,
                            wAPSMarginCapacityAndResult, wOrderRoutePartPointMap, 0, wFPCRoutePartPoint, false,
                            wAllowTechDelayHour);


                    wAPSMarginCapacityAndResult.AddToTotal();

                    if (wMarginCapacityT <= 0)
                        break;
                    wRouteStartDate.add(Calendar.DAY_OF_MONTH, 1);
                }
                if (wMarginCapacityT > 0) {
                    wAPSMessage.add(new APSMessage(APSMsgTypes.Capacity.getValue(), wOMSOrder.ID, wOMSOrder.LineID,
                            wOMSOrder.ProductCode,

                            StringUtils.Format("订单：{0} 排程时产能不足未排完！", wOMSOrder.Code)));
                }
            }
            wOrderTaskPartPointList = wAPSMarginCapacityAndResult.CreateAPSTaskPartPointList(wLoginUser,
                    wAPSShiftPeriod, wOMSOrder, wOrderRoutePartPointMap);

            if (wOrderTaskPartPointList != null && wOrderTaskPartPointList.size() > 0) {

                wResult.addAll(wOrderTaskPartPointList);
            }
        }
        return wResult;
    }


    /**
     * @param wLoginUser
     * @param wTaskPartList
     * @param wFPCRoutePartPointListMap
     * @param wMarginRoutePartPointListMap
     * @param wAPSTaskPartPointDoneListMap
     * @param wMarginEntityCapacityMap
     * @param wAPSMessage
     * @param wStartDate
     * @param wEndDate
     * @return
     */
    public List<APSTaskPartPoint> APS_AutoTaskPartPointByTaskPart(BMSEmployee wLoginUser,
                                                                  List<APSTaskPart> wTaskPartList,
                                                                  APSShiftPeriod wAPSShiftPeriod,
                                                                  Map<Integer, List<FPCRoutePartPoint>> wFPCRoutePartPointListMap,
                                                                  Map<String, List<List<FPCRoutePartPoint>>> wMarginRoutePartPointListMap,
                                                                  Map<String, List<APSTaskPartPoint>> wAPSTaskPartPointDoneListMap,
                                                                  Map<Integer, APSMarginEntityCapacity> wMarginEntityCapacityMap, int wAllowTechDelayHour,
                                                                  List<APSMessage> wAPSMessage, Calendar wStartDate,
                                                                  Calendar wEndDate) {

        List<APSTaskPartPoint> wResult = new ArrayList<APSTaskPartPoint>();

        Map<Integer, FPCRoutePartPoint> wPartRoutePartPointMap = new HashMap<Integer, FPCRoutePartPoint>();
        List<List<FPCRoutePartPoint>> wMarginRoutePartPointList = new ArrayList<>();
        List<APSTaskPartPoint> wOrderTaskPartPointList = null;
        Map<Integer, APSTaskPartPoint> wDoneTaskPartPointMap = null;

        APSMarginCapacityAndResult wAPSMarginCapacityAndResult =
                new APSMarginCapacityAndResult(wMarginEntityCapacityMap, true);


        // Map<Integer, Calendar> wStartedPartPointDate = new HashMap<>();
        Calendar wRouteStartDate;
        Calendar wPartPointStartDate;
        Calendar wPlanCalendar = CalendarTool.CloneDateTime(wStartDate);
        for (APSTaskPart wAPSTaskPart : wTaskPartList) {
            wPartRoutePartPointMap =
                    wFPCRoutePartPointListMap.get(wAPSTaskPart.RoutePartID).stream().collect(Collectors.toMap(p -> p.ID, p -> p, (o1, o2) -> o1));
            wMarginRoutePartPointList =
                    wMarginRoutePartPointListMap.get(wAPSTaskPart.OrderID + "_" + wAPSTaskPart.RoutePartID);

            if (wAPSTaskPartPointDoneListMap.containsKey(wAPSTaskPart.OrderID + "_" + wAPSTaskPart.RoutePartID)) {
                wAPSTaskPart.TaskPartPointList.addAll(wAPSTaskPartPointDoneListMap.get(wAPSTaskPart.OrderID + "_" + wAPSTaskPart.RoutePartID));
                wDoneTaskPartPointMap =
                        wAPSTaskPart.TaskPartPointList.stream().collect(Collectors.toMap(p -> p.RoutePartPointID,
                                p -> p, (o1, o2) -> o1));
            } else {
                wDoneTaskPartPointMap = new HashMap<>();
            }

            wAPSMarginCapacityAndResult.ClearResult();

            wPlanCalendar = CalendarTool.CloneDateTime(wAPSTaskPart.PartStartTime);


            wMarginRoutePartPointList.sort((o1, o2) -> o2.size() - o1.size());


            float wMarginCapacityT = 0;

            //获取最小批量
            List<APSDoneMinSchedule> wPrevPartPointMinScheduleMap =
                    iPlantSchedulePartPointTools.getInstance().GetPrevPartPointMinSchduleList(wDoneTaskPartPointMap,
                            wAPSTaskPart.PlantNum);


            //获取待排程初始工艺 只需要一个就够了
            if (wMarginRoutePartPointList.size() == 0 || wMarginRoutePartPointList.get(0).size() == 0) {

                //剩余无任务 无需重排
                continue;
            }
            FPCRoutePartPoint wFPCRoutePartPoint = wMarginRoutePartPointList.get(0).get(0);

            wRouteStartDate = CalendarTool.CloneDateTime(wPlanCalendar);

            Map<Integer, Map<String, Float>> wResultMap = new HashMap<>();
            if (wPrevPartPointMinScheduleMap != null && wPrevPartPointMinScheduleMap.size() > 0) {
                while (CalendarTool.CompareDate(wRouteStartDate, wEndDate) <= 0) {

                    int wLength = wPrevPartPointMinScheduleMap.size();
                    for (int i = 0; i < wLength; i++) {
                        wMarginCapacityT = wPrevPartPointMinScheduleMap.get(i).MinPlan;


                        wMarginCapacityT -= iPlantSchedulePartPointTools.getInstance().GetPartPointMaxCapacity(wLoginUser,
                                wPrevPartPointMinScheduleMap.get(i).TechnologyList, wPlanCalendar, wRouteStartDate,
                                wMarginCapacityT,
                                wAPSMarginCapacityAndResult, wPartRoutePartPointMap, 0, wFPCRoutePartPoint, false,
                                wAllowTechDelayHour);

                        if (wMarginCapacityT > 0) {
                            //当日产能不够
                            wPrevPartPointMinScheduleMap.get(i).MinPlan = wMarginCapacityT;
                            break;
                        } else {
                            //产能足够
                            wPrevPartPointMinScheduleMap.remove(i);
                            i--;
                            wLength--;
                        }

                    }
                    if (wPrevPartPointMinScheduleMap.size() == 0)
                        break;

                    wRouteStartDate.add(Calendar.DAY_OF_MONTH, 1);
                }
                if (wPrevPartPointMinScheduleMap.size() > 0) {
                    wAPSMessage.add(new APSMessage(APSMsgTypes.Capacity.getValue(), wAPSTaskPart.OrderID,
                            wAPSTaskPart.LineID, wAPSTaskPart.ProductCode,

                            StringUtils.Format("订单：{0} 工艺：{1} 排程时产能不足未排完！", wAPSTaskPart.OrderNo,
                                    wAPSTaskPart.RoutePartName)));
                }

            } else {
                wMarginCapacityT = wAPSTaskPart.PlantNum;
                while (CalendarTool.CompareDate(wRouteStartDate, wEndDate) <= 0) {


                    wMarginCapacityT -= iPlantSchedulePartPointTools.getInstance().GetPartPointMaxCapacity(wLoginUser,
                            new HashMap<>(), wPlanCalendar, wRouteStartDate, wMarginCapacityT,
                            wAPSMarginCapacityAndResult, wPartRoutePartPointMap, 0, wFPCRoutePartPoint, false,
                            wAllowTechDelayHour);


                    wAPSMarginCapacityAndResult.AddToTotal();

                    if (wMarginCapacityT <= 0)
                        break;
                    wRouteStartDate.add(Calendar.DAY_OF_MONTH, 1);
                }
                if (wMarginCapacityT > 0) {
                    wAPSMessage.add(new APSMessage(APSMsgTypes.Capacity.getValue(), wAPSTaskPart.OrderID,
                            wAPSTaskPart.LineID, wAPSTaskPart.ProductCode,

                            StringUtils.Format("订单：{0} 工艺：{1} 排程时产能不足未排完！", wAPSTaskPart.OrderNo,
                                    wAPSTaskPart.RoutePartName)));
                }
            }
            wOrderTaskPartPointList = wAPSMarginCapacityAndResult.CreateAPSTaskPartPointList(wLoginUser,
                    wAPSShiftPeriod, wAPSTaskPart, wPartRoutePartPointMap);


            wAPSTaskPart.TaskPartPointList.addAll(wOrderTaskPartPointList);


            wResult.addAll(wOrderTaskPartPointList);
        }
        return wResult;
    }


    /**
     * 获取实体对应班次信息
     *
     * @param wLoginUser
     * @param wFPCRouteType
     * @param wEntityIDList
     * @param wFPCProductMap
     * @param wStartDate
     * @param wEndDate
     * @param wShiftListMap
     * @param wCalendarListMap
     * @param wCapacityEntityMap
     * @param wAPSMessage
     */
    public void SetShiftInfo(BMSEmployee wLoginUser, FPCRouteType wFPCRouteType, List<Integer> wEntityIDList,
                             Map<Integer, FPCProduct> wFPCProductMap, Calendar wStartDate, Calendar wEndDate,
                             Map<Integer, List<FMCShift>> wShiftListMap,
                             Map<Integer, List<CFGCalendar>> wCalendarListMap, Map<Integer, Map<Integer,
            List<FPCCapacity>>> wCapacityEntityMap, List<APSMessage> wAPSMessage) {

        ServiceResult<List<CFGCalendar>> wCFGCalendarServiceResult = null;
        ServiceResult<List<FPCCapacity>> wFPCCapacityServiceResult = null;
        ServiceResult<List<FMCShift>> wFMCShiftServiceResult = null;
        Map<Integer, List<FPCCapacity>> wCapacityMap = new HashMap<>();

        switch (wFPCRouteType) {
            case RoutePartWorkshop:

                FMCWorkshop wFMCWorkshop;
                for (Integer wEntityID : wEntityIDList) {
                    wFMCWorkshop = CacheUtils.GetCacheInfo(FMCWorkshop.class, wEntityID, "");
                    if (wFMCWorkshop == null || wFMCWorkshop.ID <= 0 || wFMCWorkshop.Active != 1) {
                        wAPSMessage.add(new APSMessage(APSMsgTypes.Lack.getValue(), 0, 0, "",
                                StringUtils.Format("工艺配置的车间(ID:{0})不存在或无效！", wEntityID)));
                        continue;
                        //抛出异常
                    }
                    wCFGCalendarServiceResult = CFGServiceImpl.getInstance().CFG_QueryHoliday(wLoginUser,
                            wFMCWorkshop.FactoryID, wFMCWorkshop.ID, 0, 0, 0, 0, wStartDate, wEndDate, 1,
                            Pagination.getNewMaxSize());

                    if (wCFGCalendarServiceResult == null || StringUtils.isNotEmpty(wCFGCalendarServiceResult.FaultCode) ||
                            wCFGCalendarServiceResult.Result == null || wCFGCalendarServiceResult.Result.size() == 0) {
                        wAPSMessage.add(new APSMessage(APSMsgTypes.Lack.getValue(), 0, 0, "",
                                StringUtils.Format("工艺配置的车间(ID:{0})对应的班次日历查询失败！", wEntityID)));
                    }

                    wCalendarListMap.put(wEntityID, wCFGCalendarServiceResult.Result);


                    wFMCShiftServiceResult = FMCServiceImpl.getInstance().FMC_QueryShiftList(wLoginUser,
                            wFMCWorkshop.FactoryID,
                            wFMCWorkshop.ID, 0, 0, Pagination.getNewMaxSize());


                    if (wFMCShiftServiceResult == null || StringUtils.isNotEmpty(wFMCShiftServiceResult.FaultCode) ||
                            wFMCShiftServiceResult.Result == null || wFMCShiftServiceResult.Result.size() == 0) {
                        wAPSMessage.add(new APSMessage(APSMsgTypes.Lack.getValue(), 0, 0, "",
                                StringUtils.Format("工艺配置的车间(ID:{0})对应的班次配置查询失败！", wEntityID)));
                    }

                    wShiftListMap.put(wEntityID, wFMCShiftServiceResult.Result);

                    wCapacityMap = new HashMap<>();
                    for (Integer wProductID : wFPCProductMap.keySet()) {
                        wFPCCapacityServiceResult = FPCServiceImpl.getInstance().FPC_CreateCapacityList(wLoginUser,
                                wProductID, wFMCWorkshop.FactoryID,
                                wFMCWorkshop.ID, 0, 0);


                        if (wFPCCapacityServiceResult == null || StringUtils.isNotEmpty(wFPCCapacityServiceResult.FaultCode) ||
                                wFPCCapacityServiceResult.Result == null || wFPCCapacityServiceResult.Result.size() == 0) {
                            wAPSMessage.add(new APSMessage(APSMsgTypes.Lack.getValue(), 0, 0, "",
                                    StringUtils.Format("产品({1})工艺配置的车间(ID:{0})对应的产能配置查询失败！", wEntityID,
                                            wFPCProductMap.get(wProductID).Code)));
                        }
                        wCapacityMap.put(wProductID, wFPCCapacityServiceResult.Result);
                    }
                    wCapacityEntityMap.put(wEntityID, wCapacityMap);

                }

                break;
            case RoutePartWorkArea:
                FMCWorkArea wFMCWorkArea;
                for (Integer wEntityID : wEntityIDList) {
                    wFMCWorkArea = CacheUtils.GetCacheInfo(FMCWorkArea.class, wEntityID, "");
                    if (wFMCWorkArea == null || wFMCWorkArea.ID <= 0 || wFMCWorkArea.Active != 1) {
                        wAPSMessage.add(new APSMessage(APSMsgTypes.Lack.getValue(), 0, 0, "",
                                StringUtils.Format("工艺配置的工区(ID:{0})不存在或无效！", wEntityID)));
                        continue;
                        //抛出异常
                    }
                    wCFGCalendarServiceResult = CFGServiceImpl.getInstance().CFG_QueryHoliday(wLoginUser,
                            wFMCWorkArea.FactoryID, wFMCWorkArea.WorkshopID, wFMCWorkArea.ID, 0, 0, 0, wStartDate,
                            wEndDate, 1, Pagination.getNewMaxSize());

                    if (wCFGCalendarServiceResult == null || StringUtils.isNotEmpty(wCFGCalendarServiceResult.FaultCode) ||
                            wCFGCalendarServiceResult.Result == null || wCFGCalendarServiceResult.Result.size() == 0) {
                        wAPSMessage.add(new APSMessage(APSMsgTypes.Lack.getValue(), 0, 0, "",
                                StringUtils.Format("工艺配置的工区(ID:{0})对应的班次日历查询失败！", wEntityID)));
                    }

                    wCalendarListMap.put(wEntityID, wCFGCalendarServiceResult.Result);


                    wFMCShiftServiceResult = FMCServiceImpl.getInstance().FMC_QueryShiftList(wLoginUser,
                            wFMCWorkArea.FactoryID, wFMCWorkArea.WorkshopID, wFMCWorkArea.ID, 0,
                            Pagination.getNewMaxSize());


                    if (wFMCShiftServiceResult == null || StringUtils.isNotEmpty(wFMCShiftServiceResult.FaultCode) ||
                            wFMCShiftServiceResult.Result == null || wFMCShiftServiceResult.Result.size() == 0) {
                        wAPSMessage.add(new APSMessage(APSMsgTypes.Lack.getValue(), 0, 0, "",
                                StringUtils.Format("工艺配置的工区(ID:{0})对应的班次配置查询失败！", wEntityID)));
                    }

                    wShiftListMap.put(wEntityID, wFMCShiftServiceResult.Result);


                    wCapacityMap = new HashMap<>();
                    for (Integer wProductID : wFPCProductMap.keySet()) {
                        wFPCCapacityServiceResult = FPCServiceImpl.getInstance().FPC_CreateCapacityList(wLoginUser,
                                wProductID,
                                wFMCWorkArea.FactoryID, wFMCWorkArea.WorkshopID, wFMCWorkArea.ID, 0);


                        if (wFPCCapacityServiceResult == null || StringUtils.isNotEmpty(wFPCCapacityServiceResult.FaultCode) ||
                                wFPCCapacityServiceResult.Result == null || wFPCCapacityServiceResult.Result.size() == 0) {
                            wAPSMessage.add(new APSMessage(APSMsgTypes.Lack.getValue(), 0, 0, "",
                                    StringUtils.Format("产品({1})工艺配置的工区(ID:{0})对应的产能配置查询失败！", wEntityID,
                                            wFPCProductMap.get(wProductID).Code)));
                        }
                        wCapacityMap.put(wProductID, wFPCCapacityServiceResult.Result);
                    }
                    wCapacityEntityMap.put(wEntityID, wCapacityMap);

                }
                break;
            case RoutePartStation:
            case RoutePartPoint:

                FMCStation wFMCStation;
                for (Integer wEntityID : wEntityIDList) {
                    wFMCStation = CacheUtils.GetCacheInfo(FMCStation.class, wEntityID, "");
                    if (wFMCStation == null || wFMCStation.ID <= 0 || wFMCStation.Active != 1) {
                        wAPSMessage.add(new APSMessage(APSMsgTypes.Lack.getValue(), 0, 0, "",
                                StringUtils.Format("工艺配置的工位(ID:{0})不存在或无效！", wEntityID)));
                        continue;
                    }
                    wCFGCalendarServiceResult = CFGServiceImpl.getInstance().CFG_QueryHoliday(wLoginUser,
                            wFMCStation.FactoryID, wFMCStation.WorkshopID, wFMCStation.WorkAreaID, wFMCStation.ID, 0, 0,
                            wStartDate, wEndDate, 1, Pagination.getNewMaxSize());

                    if (wCFGCalendarServiceResult == null || StringUtils.isNotEmpty(wCFGCalendarServiceResult.FaultCode) ||
                            wCFGCalendarServiceResult.Result == null || wCFGCalendarServiceResult.Result.size() == 0) {
                        wAPSMessage.add(new APSMessage(APSMsgTypes.Lack.getValue(), 0, 0, "",
                                StringUtils.Format("工艺配置的工位(ID:{0})对应的班次日历查询失败！", wEntityID)));
                    }
                    wCalendarListMap.put(wEntityID, wCFGCalendarServiceResult.Result);

                    wFMCShiftServiceResult = FMCServiceImpl.getInstance().FMC_QueryShiftList(wLoginUser,
                            wFMCStation.FactoryID, wFMCStation.WorkshopID, wFMCStation.WorkAreaID, wFMCStation.ID,
                            Pagination.getNewMaxSize());


                    if (wFMCShiftServiceResult == null || StringUtils.isNotEmpty(wFMCShiftServiceResult.FaultCode) ||
                            wFMCShiftServiceResult.Result == null || wFMCShiftServiceResult.Result.size() == 0) {
                        wAPSMessage.add(new APSMessage(APSMsgTypes.Lack.getValue(), 0, 0, "",
                                StringUtils.Format("工艺配置的工位(ID:{0})对应的班次配置查询失败！", wEntityID)));
                    }
                    wShiftListMap.put(wEntityID, wFMCShiftServiceResult.Result);


                    wCapacityMap = new HashMap<>();
                    for (Integer wProductID : wFPCProductMap.keySet()) {
                        wFPCCapacityServiceResult = FPCServiceImpl.getInstance().FPC_CreateCapacityList(wLoginUser,
                                wProductID,
                                wFMCStation.FactoryID, wFMCStation.WorkshopID, wFMCStation.WorkAreaID, wFMCStation.ID);


                        if (wFPCCapacityServiceResult == null || StringUtils.isNotEmpty(wFPCCapacityServiceResult.FaultCode) ||
                                wFPCCapacityServiceResult.Result == null || wFPCCapacityServiceResult.Result.size() == 0) {
                            wAPSMessage.add(new APSMessage(APSMsgTypes.Lack.getValue(), 0, 0, "",
                                    StringUtils.Format("产品({1})工艺配置的工位(ID:{0})对应的产能配置查询失败！", wEntityID,
                                            wFPCProductMap.get(wProductID).Code)));
                        }
                        wCapacityMap.put(wProductID, wFPCCapacityServiceResult.Result);
                    }
                    wCapacityEntityMap.put(wEntityID, wCapacityMap);
                }
                break;
            case Default:
            default:
                break;

        }

    }


    public Map<Integer, List<FMCUnavailable>> GetEntityUnavailableList(List<FMCUnavailable> wUnavailableList,
                                                                       FPCRouteType wFPCRouteType) {

        Map<Integer, List<FMCUnavailable>> wResult = new HashMap<>();
        List<FMCWorkshop> wWorkshopList = CacheUtils.GetCacheTList(FMCWorkshop.class);
        List<FMCWorkArea> wWorkAreaList = CacheUtils.GetCacheTList(FMCWorkArea.class);
        List<FMCStation> wStationList = CacheUtils.GetCacheTList(FMCStation.class);
        for (FMCUnavailable wFMCUnavailable : wUnavailableList) {
            switch (wFPCRouteType) {


                case RoutePartWorkshop:
                    if (wFMCUnavailable.WorkshopID > 0 && wFMCUnavailable.WorkAreaID == 0) {

                        if (!wResult.containsKey(wFMCUnavailable.WorkshopID))
                            wResult.put(wFMCUnavailable.WorkshopID, new ArrayList<>());

                        wResult.get(wFMCUnavailable.WorkshopID).add(wFMCUnavailable);
                    }
                    if (wFMCUnavailable.WorkshopID == 0 && wFMCUnavailable.FactoryID > 0) {
                        //获取此工厂下所有车间
                        for (FMCWorkshop wFMCWorkshop : wWorkshopList) {
                            if (wFMCWorkshop == null || wFMCWorkshop.ID <= 0 || wFMCWorkshop.Active != 1 || wFMCWorkshop.FactoryID != wFMCUnavailable.FactoryID)
                                continue;
                            if (!wResult.containsKey(wFMCWorkshop.ID))
                                wResult.put(wFMCWorkshop.ID, new ArrayList<>());

                            wResult.get(wFMCWorkshop.ID).add(wFMCUnavailable);
                        }
                    }
                    break;
                case RoutePartWorkArea:

                    if (wFMCUnavailable.WorkAreaID > 0 && wFMCUnavailable.StationID == 0) {

                        if (!wResult.containsKey(wFMCUnavailable.WorkAreaID))
                            wResult.put(wFMCUnavailable.WorkAreaID, new ArrayList<>());

                        wResult.get(wFMCUnavailable.WorkAreaID).add(wFMCUnavailable);
                    }

                    if ((wFMCUnavailable.WorkshopID > 0 && wFMCUnavailable.WorkAreaID == 0)
                            || (wFMCUnavailable.WorkshopID == 0 && wFMCUnavailable.FactoryID > 0)) {

                        for (FMCWorkArea wFMCWorkArea : wWorkAreaList) {
                            if (wFMCWorkArea == null || wFMCWorkArea.ID <= 0 || wFMCWorkArea.Active != 1)
                                continue;
                            if (wFMCUnavailable.WorkshopID > 0 && wFMCWorkArea.WorkshopID != wFMCUnavailable.WorkshopID)
                                continue;
                            if (wFMCUnavailable.FactoryID > 0 && wFMCWorkArea.FactoryID != wFMCUnavailable.FactoryID)
                                continue;

                            if (!wResult.containsKey(wFMCWorkArea.ID))
                                wResult.put(wFMCWorkArea.ID, new ArrayList<>());

                            wResult.get(wFMCWorkArea.ID).add(wFMCUnavailable);
                        }
                    }


                    break;
                case RoutePartStation:
                case RoutePartPoint:

                    if (wFMCUnavailable.StationID > 0) {

                        if (!wResult.containsKey(wFMCUnavailable.StationID))
                            wResult.put(wFMCUnavailable.StationID, new ArrayList<>());

                        wResult.get(wFMCUnavailable.StationID).add(wFMCUnavailable);
                    }


                    if ((wFMCUnavailable.WorkAreaID > 0 && wFMCUnavailable.StationID == 0) || (wFMCUnavailable.WorkshopID > 0 && wFMCUnavailable.WorkAreaID == 0)
                            || (wFMCUnavailable.WorkshopID == 0 && wFMCUnavailable.FactoryID > 0)) {

                        for (FMCStation wFMCStation : wStationList) {
                            if (wFMCStation == null || wFMCStation.ID <= 0 || wFMCStation.Active != 1)
                                continue;
                            if (wFMCUnavailable.WorkAreaID > 0 && wFMCStation.WorkAreaID != wFMCUnavailable.WorkAreaID)
                                continue;
                            if (wFMCUnavailable.WorkshopID > 0 && wFMCStation.WorkshopID != wFMCUnavailable.WorkshopID)
                                continue;
                            if (wFMCUnavailable.FactoryID > 0 && wFMCStation.FactoryID != wFMCUnavailable.FactoryID)
                                continue;

                            if (!wResult.containsKey(wFMCStation.ID))
                                wResult.put(wFMCStation.ID, new ArrayList<>());

                            wResult.get(wFMCStation.ID).add(wFMCUnavailable);
                        }
                    }

                    break;
                case Default:
                    break;
            }

        }
        return wResult;
    }


}
